﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Globalization;
using System.Collections;
using System.Windows.Controls;
using ResourceBlender.Core;

namespace ResourceBlender.Express.Converters {
    /// <summary>
    /// Converts a list of language codes to a list of &lt;code, englishName&gt;
    /// </summary>
    public class LanguageCodeListConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            List<string> codes = value as List<string>;
            ObservableSortedDictionary<string, CultureInfo> items = new ObservableSortedDictionary<string, CultureInfo>(new Comparers.CultureInfoEnglshNameComparer(), new Comparers.StringEqualityComparer());
            foreach(string code in codes) {
                CultureInfo info = Utils.GetCultureInfo(code);
                if(code != null) {
                    items.Add(code, info);
                }
            }
            return items;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a language code to it's english name if the code is supported by GetCultureInfo
    /// </summary>
    public class LanguageCodeConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            try {
                return CultureInfo.GetCultureInfo(value.ToString()).EnglishName;
            } catch {
                return value;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a list of language codes to a string containing all codes, sorted by name
    /// </summary>
    public class LanguageCodeListStringifier : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || !(value is IEnumerable<string>)) return null;
            IEnumerable<string> languageCodes = value as IEnumerable<string>;
            int numLanguages = languageCodes.Count();
            List<string> languageNames = new List<string>();
            foreach(string code in languageCodes) {
                try {
                    languageNames.Add(CultureInfo.GetCultureInfo(code).EnglishName);
                } catch {
                    languageNames.Add(code);
                }
            }
            languageNames.Sort();
            return Utils.Implode(languageNames, ", ", false);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a List&lt;String&gt; of strings to a string containing all strings, separated by unix line breaks (\n)
    /// </summary>
    public class ListToStringConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || !(value is List<string>)) return null;
            List<string> list = value as List<string>;
            StringBuilder buffer = new StringBuilder();
            int num = list.Count,
                added = 0;
            foreach(string item in list) {
                buffer.Append(item);
                if(added + 1 < num) {
                    buffer.Append('\n');
                }
                added++;
            }
            return buffer.ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            return value.ToString().Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
        }
    }

    /// <summary>
    /// Returns true if the value is "java"
    /// </summary>
    public class CanEscapeUnicodeConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            switch ((value ?? string.Empty).ToString().ToLowerInvariant()) {
                case "java":
                case "firefox":
                    return true;
                default:
                    return false;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Formats a string displaying duplicate data
    /// Assumes there are two bindings and a parameter, the first is the number of duplicates, the second is the language code, the parameter is the string format
    /// </summary>
    public class DuplicateFormatter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            if(values == null) return null;
            string englishName;
            try {
                englishName = CultureInfo.GetCultureInfo(values[1].ToString()).EnglishName;
            } catch {
                englishName = values[1].ToString();
            }
            return string.Format((parameter ?? string.Empty).ToString(), values[0], englishName);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a dictionary of bundles to a string, sorted by bundle name
    /// </summary>
    public class BundleNameStringifier : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            string[] bundleNames = (value as IDictionary<string, string>).Values.ToArray();
            int numBundles = bundleNames.Length;
            StringBuilder buffer = new StringBuilder();
            for(int i = 0; i < numBundles; i++) {
                buffer.Append(bundleNames[i]);
                if(i < numBundles - 1) {
                    buffer.Append(", ");
                }
            }
            return buffer.ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a ChangeableBundle.ChangeMode to an image which represnts the mode.
    /// </summary>
    public class ActionToImage : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            BitmapImage img = null;
            string imageName = string.Empty;
            if(value is KeyValuePair<string, ChangeableBundle>) {
                switch(((KeyValuePair<string, ChangeableBundle>)value).Value.Mode) {
                    case ChangeableBundle.ChangeMode.None:
                        imageName = "pack://application:,,,/Resources/images/bundle_16.png";
                        break;
                    case ChangeableBundle.ChangeMode.Add:
                        imageName = "pack://application:,,,/Resources/images/bundle_add_16.png";
                        break;
                    case ChangeableBundle.ChangeMode.Edit:
                        imageName = "pack://application:,,,/Resources/images/bundle_edit_16.png";
                        break;
                    case ChangeableBundle.ChangeMode.Delete:
                        imageName = "pack://application:,,,/Resources/images/bundle_delete_16.png";
                        break;
                }
            }
            try {
                img = new BitmapImage(new Uri(imageName, UriKind.Absolute));
            } catch {
                img = new BitmapImage();
            }
            return img;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a CultureInfo to a string representing a flag image for that culture.
    /// </summary>
    public class CultureInfoToFlagConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null || !(value is CultureInfo)) {
                return null;
            } else {
                return string.Format("pack://application:,,,/Resources/images/flags/{0}.png", Utils.GetISO3166(value as CultureInfo));
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a format name to an image.
    /// </summary>
    public class FormatToImageConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            BitmapImage img = null;
            string imageName = string.Empty;
            if(value is KeyValuePair<string, string>) {
                KeyValuePair<string, string> boundValue = (KeyValuePair<string, string>)value;
                string formatName = boundValue.Value;
                int formatId;
                if(!int.TryParse(formatName, out formatId)) { // if it's a Constants.ResourceType, neither field will be an integer. Templates IDs autoincrement.
                    try {
                        Constants.ResourceType formatType = (Constants.ResourceType)Enum.Parse(typeof(Constants.ResourceType), formatName, true);
                        switch(formatType) {
                            case Constants.ResourceType.DotNet:
                                imageName = "pack://application:,,,/Resources/images/page_white_visualstudio.png";
                                break;
                            case Constants.ResourceType.DotNetCF:
                                imageName = "pack://application:,,,/Resources/images/pda.png";
                                break;
                            case Constants.ResourceType.Firefox:
                                imageName = "pack://application:,,,/Resources/images/page_white_mozilla.png";
                                break;
                            case Constants.ResourceType.Java:
                                imageName = "pack://application:,,,/Resources/images/page_white_java.png";
                                break;
                            case Constants.ResourceType.PO:
                                imageName = "pack://application:,,,/Resources/images/page_white_tux.png";
                                break;
                        }
                    } catch { }
                }
                if(imageName == string.Empty) {
                    if(boundValue.Key.ToLower().Contains("php")) {
                        imageName = "pack://application:,,,/Resources/images/page_white_php.png";
                    } else {
                        imageName = "pack://application:,,,/Resources/images/templates_16.png";
                    }
                }
            }
            try {
                img = new BitmapImage(new Uri(imageName, UriKind.Absolute));
            } catch {
                img = new BitmapImage();
            }
            return img;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Returns a boolean value to indicate whether an RBApplication contains at least one bundle and language, making it valid for resource editing.
    /// </summary>
    public class CanEditAppConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            ObservableApplication app = ((KeyValuePair<string, ObservableApplication>)value).Value;
            if(app == null) {
                return false;
            } else {
                return app.Languages.Count > 0 && app.Bundles.Count > 0;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Calculates the column width required to fill the view in a GridView
    /// </summary>
    public class WidthConverter : IValueConverter {
        /// <summary>
        /// Converts the specified value.
        /// </summary>
        /// <param name="value">The parent Listview.</param>
        /// <param name="type">The type.</param>
        /// <param name="parameter">
        /// If no parameter is given, the remaning with will be returned.
        /// If the parameter is an integer acts as MinimumWidth, the remaining with will be returned only if it's greater than the parameter
        /// If the parameter is anything else, it's taken to be a percentage. Eg: 0.3* = 30%, 0.15* = 15%
        /// </param>
        /// <param name="culture">The culture.</param>
        /// <returns>The width, as calculated by the parameter given</returns>
        public object Convert(object value, Type type, object parameter, CultureInfo culture) {
            if(value == null) return null;
            ListView listView = value as ListView;
            GridView grdView = listView.View as GridView;
            int minWidth = 0;
            bool widthIsPercentage = parameter != null && !int.TryParse(parameter.ToString(), out minWidth);
            if(widthIsPercentage) {
                string widthParam = parameter.ToString();
                double percentage = double.Parse(widthParam.Substring(0, widthParam.Length - 1));
                return listView.ActualWidth * percentage;
            } else {
                double total = 0;
                for(int i = 0; i < grdView.Columns.Count - 1; i++) {
                    total += grdView.Columns[i].ActualWidth;
                }
                double remainingWidth = listView.ActualWidth - total;
                if(remainingWidth > minWidth) { // fill the remaining width in the ListView
                    return remainingWidth;
                } else { // fill remaining space with MinWidth
                    return minWidth;
                }
            }
        }

        public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) {
            throw new NotSupportedException();
        }
    }

    /// <summary>
    /// Provides a breakpoint for debugging
    /// </summary>
    public class DebugConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    #region Converters for the WPF toolkit Datagrid
    public class BoolToOpacityConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            try {
                bool b = (bool)value;
                if(b) return 1; else return 0;
            } catch {
                return 1;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    public class ObjectToTypeName : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            if(value != null) {
                return value.GetType().Name;
            } else {
                return null;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
            throw new NotImplementedException();
        }
    }
    #endregion
}
